import fs from "fs"
import { Buffer } from "buffer";
import path, { resolve, relative } from "path";
import { IpcMainEvent } from "electron"
import dayjs from "dayjs"
import { mkdirSync, existsSync, createReadStream, createWriteStream, appendFileSync, writeFileSync } from "fs";
import imagemin from "imagemin";
import imageminPngquant from "imagemin-pngquant"; // png 压缩
import imageminMozjpeg from 'imagemin-mozjpeg'; // jpg 压缩
import { FileInfo, CurrentFile, CurrentFileList, DealRequire, DealResult, CompressResult } from "../src/types";

export const logPath = resolve(process.cwd(), "log")

// 图片
const imageBufferHeaders = [
  { bufBegin: [0xff, 0xd8], bufEnd: [0xff, 0xd9], suffix: ".jpg" },
  {
    bufBegin: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],
    suffix: ".png",
  },
];


export function fromatFileInfo(file: FileInfo): FileInfo | null {
  let filebuf;
  try {
    filebuf = fs.readFileSync(file.path, "hex");
    const fileHex = Buffer.from(filebuf, "hex");
    const extname = getPicExtname(fileHex)
    if (extname) {
      file.extname = extname
      return file
    }
  } catch (error) {
    console.log(error);
    return null;
  }
  return null
}


export function getPicExtname(fileBuffer: Buffer): string {
  for (const bufferHeader of imageBufferHeaders) {
    let isEqual: boolean; // 判断标识头前缀
    if (bufferHeader.bufBegin) {
      const buf = Buffer.from(bufferHeader.bufBegin);
      isEqual = buf.equals(
        //使用 buffer.slice 方法 对 buffer 以字节为单位切割
        fileBuffer.slice(0, bufferHeader.bufBegin.length)
      );
    } // 判断标识头后缀
    if (isEqual && bufferHeader.bufEnd) {
      const buf = Buffer.from(bufferHeader.bufEnd);
      isEqual = buf.equals(fileBuffer.slice(-bufferHeader.bufEnd.length));
    }
    if (isEqual) {
      return bufferHeader.suffix;
    }
  }
  return '';
}

export function getAllFile(dir: string, initDir: string = dir) {
  let fileList = [] as string[],
    list = [] as FileInfo[];
  try {
    fileList = fs.readdirSync(dir);
    fileList.forEach((item) => {
      let filepath = path.join(dir, item);
      const current = fs.statSync(filepath);
      if (current.isDirectory()) {
        list.push(...getAllFile(filepath, initDir));
      } else {
        list.push({
          path: filepath,
          relativePath: relative(initDir, filepath),
          size: current.size,
          name: item,
          birthtime: dayjs("2021-12-28T02:44:43.453Z").format("YYYY-MM-DD HH:mm:ss"),
          sizeStr: transformSize(current.size)
        });
      }
    });
  } catch (error) {
    console.log(error);
  }
  return list;
}

function transformSize(size: number): string {
  const divisor = 1024
  const result = (size / divisor)
  if (result > divisor) {
    return (result / divisor).toFixed(2) + 'MB'
  }
  return result.toFixed(2) + 'kb'
}


export function isExitsDir(dir: string) {
  try {
    if (!existsSync(dir)) {
      mkdirSync(dir);
    }
  } catch (error) {
    writeLog(error, "err")
  }

}

export function isExitsFile(filepath: string): boolean {
  return existsSync(filepath)
}

export function compressIMG(fileInfo: CurrentFile, positionPath: string, quality: number, isRelative: Boolean): Promise<CompressResult> {
  let destination = isRelative ? resolve(positionPath, fileInfo.relativePath.replace(fileInfo.name, '') || '') : positionPath
  const failPath = resolve(positionPath, "fail")
  const outputDir = path.dirname(destination)
  isExitsDir(outputDir)
  let outputPath = resolve(failPath, fileInfo.name);
  const failCb = (res) => {
    isExitsDir(failPath)
    createReadStream(fileInfo.path)
      .pipe(createWriteStream(outputPath))
      .on("close", () => {
        console.log("失败，结束了");
        res({ isSuccess: false, output: outputPath });
      });
  }
  return new Promise((res, rej) => {
    imagemin([fileInfo.path], {
      destination,
      plugins: [
        imageminPngquant({
          quality: [quality / 10, quality / 10]
        }),
        imageminMozjpeg({
          quality: quality * 10
        })
      ]
    }).then((files) => {
      if (files.length) {
        res({ isSuccess: true, output: resolve(destination, fileInfo.name) })
      } else {
        failCb(res)
      }
    }).catch((err) => {
      writeLog(err, "err")
      isExitsDir(failPath);
      failCb(res)
    })
  })
}

export function writeLog(info: any, type: string) {
  let date = dayjs().format("YYYY-MM-DD")
  let logfilePath = resolve(logPath, date + "_" + type + ".log")
  let timeStr = dayjs().format("HH:mm:ss") + ": \n"
  let end = "\n"
  try {
    isExitsDir(logPath)
    const isExits = isExitsFile(logfilePath)
    const word = timeStr + JSON.stringify(info) + end
    if (isExits) {
      appendFileSync(logfilePath, word, "utf-8")
    } else {
      writeFileSync(logfilePath, word, "utf-8")
    }
  } catch (error) {
    console.log(error);
  }
}

export function iterateCompress(list: CurrentFileList, index: number, dealRequire: DealRequire, dealResult: DealResult, event: IpcMainEvent, callback: (res: DealResult) => void) {
  if (list.length === index) {
    console.log("deal");
    callback(dealResult)
    return
  } else {
    const item = list[index]
    compressIMG(item, dealRequire.position, dealRequire.quality, dealRequire.isRelative).then((deal) => {
      if (deal.isSuccess) {
        dealResult.success += 1
        const current = fs.statSync(deal.output);
        dealResult.successList.push({
          path: deal.output,
          size: current.size,
          name: item.name,
          sizeStr: transformSize(current.size),
          oldSize: item.size,
          oldSizeStr: item.sizeStr
        })
      } else {
        dealResult.fail += 1
        dealResult.failList.push({
          path: deal.output,
          size: item.size,
          name: item.name,
          sizeStr: item.sizeStr,
          oldSize: item.size,
          oldSizeStr: item.sizeStr
        })
      }
      return dealResult
    }).then((res) => {
      event.reply("compressResult", dealResult)
      iterateCompress(list, index + 1, dealRequire, res, event, callback)
    })
  }
}